import { RouteRecordRaw } from "vue-router";
import { getRouterList } from "@/api/system/routers";
import { constantRouterIcon } from "./router-icons";
import type { AppRouteRecordRaw } from "@/router/types";
import { Layout, Iframe, ParentLayout, Page404 } from "@/router/constant";

const LayoutMap = new Map<string, () => Promise<typeof import("*.vue")>>();
LayoutMap.set("LAYOUT", Layout);
LayoutMap.set("IFRAME", Iframe);

/**
 * @description: 动态生成菜单
 */
export const generatorDynamicRouter = (): Promise<RouteRecordRaw[]> => {
  return new Promise((resolve, reject) => {
    getRouterList()
      .then((result) => {
        const routeList = routerGenerator(result);
        asyncImportRoute(routeList);

        resolve(routeList);
      })
      .catch((err) => {
        reject(err);
      });
  });
};

/**
 * @description: 格式化后端结构信息并递归生成层级路由表
 */
export const routerGenerator = (routerMap, parent?): any[] => {
  return routerMap.map((item) => {
    const currentRouter: any = {
      // 路由地址 动态拼接生成如：/dashboard/workplace； 如果后台返回的数据是拼接好的，就不需要拼接这一步
      path: `${(parent && parent.path) || ""}/${item.path}`,
      // 路由名称，建议唯一
      name: item.name || "",
      // 该路由对应页面的组件
      component: item.component,
      // meta: 页面标题，菜单图标
      meta: {
        ...item.meta,
        label: item.meta.title,
        icon: constantRouterIcon[item.meta.icon] || null,
      },
    };

    // 为了防止出现后端返回结果不规范，处理有可能出现拼接两个反斜杠
    currentRouter.path = currentRouter.path.replace("//", "/");
    // 重定向
    item.redirect && (currentRouter.redirect = item.redirect);
    // 是否有子菜单，并递归处理
    if (item.children && item.children.length > 0) {
      // 如果未定义 redirect 默认第一个子路由为 redirect
      !item.redirect &&
        (currentRouter.redirect = `${item.path}/${item.children[0].path}`);
      // 递归
      currentRouter.children = routerGenerator(item.children, currentRouter);
    }
    return currentRouter;
  });
};

/**
 * @description: 查找views中对应的组件文件
 */
let viewsModules: Record<string, () => Promise<Recordable>>;
export const asyncImportRoute = (
  routes: AppRouteRecordRaw[] | undefined
): void => {
  viewsModules = viewsModules || import.meta.glob("../views/**/*.{vue, tsx}");
  if (!routes) return;
  routes.forEach((item) => {
    if (!item.component && item.meta?.frameSrc) {
      item.component = "IFRAME";
    }
    const { component, name, children } = item;
    if (component) {
      const layoutFound = LayoutMap.get(component as string);
      // 如果LayoutMap中有component,直接赋值给component，包含layout和iframe
      if (layoutFound) {
        item.component = layoutFound;
      } else {
        // 如果LayoutMap中不包含，则进行动态导入
        item.component = dynamicImport(viewsModules, component as string);
      }
    } else if (name) {
      item.component = ParentLayout;
    }
    children && asyncImportRoute(children);
  });
};

/**
 * @description: 动态导入
 */
export const dynamicImport = (
  viewsModules: Record<string, () => Promise<Recordable>>,
  component: string
) => {
  // component是后台统一返回的，需唯一,对应views文件下的vue文件
  const keys = Object.keys(viewsModules);
  // 筛选出views下的文件与路由中包含的组件是否相同
  const matchKeys = keys.filter((key) => {
    let k = key.replace("../views", "");
    // lastIndexOf 是查某个指定的字符串在字符串最后一次出现的位置（索引值）（从右往左）
    const lastIndex = k.lastIndexOf(".");
    k = k.substring(0, lastIndex);
    return k === component;
  });

  // 如果有一个相同的，则进行动态导入
  if (matchKeys?.length === 1) {
    const matchKey = matchKeys[0];
    return viewsModules[matchKey];
  }
  // 如果有超过一个以上相同的，说明同一个component下有两个以上相同的vue文件
  if (matchKeys?.length > 1) {
    console.warn(
      "不要在views文件下创建相同层次目录的同名文件，会导致动态导入失败！"
    );
    return;
  }
  // 如果没有，说明后台配置的路径在前台没有页面，显示404
  if (matchKeys?.length === 0) {
    const matchKey = Page404;
    return viewsModules[matchKey];
  }
};
